package com.swinw.asumall.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.rabbitmq.client.Channel;
import com.swinw.asumall.order.constant.OrderConstant;
import com.swinw.asumall.order.entity.OrderItemEntity;
import com.swinw.asumall.order.entity.PaymentInfoEntity;
import com.swinw.asumall.order.feign.CartFeginService;
import com.swinw.asumall.order.feign.MemberFeignService;
import com.swinw.asumall.order.feign.ProductFeginService;
import com.swinw.asumall.order.feign.WareFeginService;
import com.swinw.asumall.order.interceptor.UserLoginInterceptor;
import com.swinw.asumall.order.service.OrderItemService;
import com.swinw.asumall.order.service.PaymentInfoService;
import com.swinw.asumall.order.vo.*;
import com.swinw.common.utils.R;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.swinw.common.utils.PageUtils;
import com.swinw.common.utils.Query;

import com.swinw.asumall.order.dao.OrderDao;
import com.swinw.asumall.order.entity.OrderEntity;
import com.swinw.asumall.order.service.OrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.HandlerInterceptor;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    @Autowired
    MemberFeignService memberFeignService;

    @Autowired
    CartFeginService cartFeginService;

    @Autowired
    OrderItemService orderItemService;

    @Autowired
    ProductFeginService productFeginService;

    @Autowired
    ThreadPoolExecutor executor;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    WareFeginService wareFeginService;

    @Autowired
    PaymentInfoService paymentInfoService;


    @RabbitListener(queues = {"java"})
    public void massage(Message message, Channel channel){
        System.out.println(message);
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        try{
            // 签收的消息编号 是否批量操作 是否退货
            if(deliveryTag % 2 == 0){
                channel.basicNack(deliveryTag,false,false);//消息签收确认
                System.out.println("签收货物编号： " + deliveryTag);
            }else{
                channel.basicNack(deliveryTag,false,true);//拒绝签收消息
                System.out.println("拒绝签收货物编号： " + deliveryTag);
            }
//            channel.basicNack(deliveryTag,false,false);//拒绝签收消息
//            channel.basicReject(deliveryTag,false);//拒绝签收信息
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 返回订单详情需要的数据
     *
     * feign在异步编排的过程中会丢失请求上下文，所以在每个异步执行的线程内都需要单独设置请求上下文
     * 如果不给子线程重新设置请求上下文，那么在执行子线程的过程中就会找不到请求上下文
     * java.lang.NullPointerException: null
     *
     * @return
     */
    @Override
    public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException {
        OrderConfirmVo orderConfirmVo = new OrderConfirmVo();
        LinkedHashMap<String, Object> map = UserLoginInterceptor.threadLocal.get();
        //获取当前主线程的请求上下文
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        Integer id = (Integer) map.get("id");
        //1、调用用户服务查询用户的收货地址表
        CompletableFuture<Void> userAddressFutrue = CompletableFuture.runAsync(() -> {
            //重新设置请求上下文
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<MemberAddressVo> memberAssressList = memberFeignService.getMemberAssressList(Long.parseLong(id + ""));
            orderConfirmVo.setAddress(memberAssressList);
        }, executor);

        //2、所有被选中的购物项
        CompletableFuture<Void> checkItemFutrue = CompletableFuture.runAsync(() -> {
            //重新设置请求上下文
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<OrderItemVo> cartItems = cartFeginService.getCartItems();
            orderConfirmVo.setItems(cartItems);
        }, executor);

        //3、用户积分信息
        orderConfirmVo.setIntegration(10);
        CompletableFuture.allOf(userAddressFutrue,checkItemFutrue).get();

        //4、设置用户令牌
        String uuid = UUID.randomUUID().toString().replace("-", "");
        stringRedisTemplate.opsForValue().set(OrderConstant.USER_ORDER_TOKEN_PRE+id,uuid,10,TimeUnit.MINUTES);
        orderConfirmVo.setToken(uuid);
        return orderConfirmVo;
    }

    @GlobalTransactional
    @Override
    public SubmitOrderResponseVo submitOrder(OrderSubmitVo vo) throws Exception {

        SubmitOrderResponseVo submitOrderResponseVo = new SubmitOrderResponseVo();

        LinkedHashMap<String, Object> map = UserLoginInterceptor.threadLocal.get();
        //获取当前主线程的请求上下文
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        Integer id = (Integer) map.get("id");
        String token = vo.getToken();

        //1、原子令牌验证及删锁
        String lua = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
        Long res = stringRedisTemplate.execute(new DefaultRedisScript<Long>(lua, Long.class),
                Arrays.asList(OrderConstant.USER_ORDER_TOKEN_PRE + id), token);
        if(res == 0){//验证失败
            submitOrderResponseVo.setCode(1);
        }else{//验证成功
            OrderEntity orderEntity = createOrder(vo);
            submitOrderResponseVo.setOrder(orderEntity);
        }

        return submitOrderResponseVo;
    }

    @Override
    public PayVo getPayVoByOrderSn(String orderSn) {
        //1、通过订单号查询订单信息
        OrderEntity orderEntity = this.baseMapper.selectOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn));
        //2、通过订单号查询订单项信息
        List<OrderItemEntity> orderItems = orderItemService.getOrderItemByOrderSn(orderSn);
        PayVo payVo = new PayVo();
        payVo.setBody(orderItems.get(0).getSkuName());
        payVo.setSubject(orderItems.get(0).getSkuAttrsVals());
        payVo.setTotal_amount(orderEntity.getTotalAmount().setScale(2).toString());
        payVo.setOut_trade_no(orderSn);
        return payVo;
    }

    /**
     * 分页查询用户订单信息
     * @param params
     * @return
     */
    @Transactional
    @Override
    public PageUtils getOrderByMemberId(Map<String, Object> params) throws ExecutionException, InterruptedException {
        //1、改变订单状态
        CompletableFuture<OrderEntity> future = CompletableFuture.supplyAsync(() -> {
            OrderEntity entity = new OrderEntity();
            entity.setOrderSn((String) params.get("out_trade_no"));
            entity.setStatus(3);
            this.baseMapper.update(entity, new UpdateWrapper<OrderEntity>().eq("order_sn", (String) params.get("out_trade_no")));
            return entity;
        }, executor);

        //2、添加订单流水
        future.thenAcceptAsync((result)->{
            PaymentInfoEntity paymentInfoEntity = new PaymentInfoEntity();
            paymentInfoEntity.setOrderId(result.getId());
            paymentInfoEntity.setOrderSn((String) params.get("out_trade_no"));
            paymentInfoEntity.setTotalAmount(new BigDecimal((String) params.get("total_amount")));
            paymentInfoEntity.setAlipayTradeNo((String)params.get("trade_no"));
            paymentInfoEntity.setCreateTime(new Date());
            paymentInfoEntity.setPaymentStatus("已支付");
            paymentInfoEntity.setConfirmTime(new Date());
            paymentInfoService.save(paymentInfoEntity);
        },executor);

        //3、查询当前登录用户的所有订单信息
        LinkedHashMap<String, Object> map = UserLoginInterceptor.threadLocal.get();
        Integer userId = (Integer) map.get("id");
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>().eq("member_id", userId)
        );
        List<OrderEntity> records = page.getRecords();
        //查询每个订单下的订单项
        List<OrderEntity> collect = records.stream().map(item -> {
            List<OrderItemEntity> order_sn = orderItemService.list(new QueryWrapper<OrderItemEntity>()
                    .eq("order_sn", item.getOrderSn()));
            item.setItemEntities(order_sn);
            return item;
        }).collect(Collectors.toList());
        page.setRecords(collect);
        return new PageUtils(page);
    }


    private OrderEntity createOrder(OrderSubmitVo vo) throws Exception {

        OrderEntity orderEntity = new OrderEntity();

        LinkedHashMap<String, Object> map = UserLoginInterceptor.threadLocal.get();
        //1、封装用户信息
        Integer userId = (Integer) map.get("id");
        MemberVo member = memberFeignService.info(Long.parseLong(userId + ""));
        orderEntity.setMemberId(member.getId());
        orderEntity.setMemberUsername(member.getUsername());

        //2、订单编号
        long orderSn = System.currentTimeMillis();
        orderEntity.setOrderSn(orderSn+"");

        //3、封装订单价钱信息
        orderEntity.setPayAmount(vo.getPayPrice());
        orderEntity.setTotalAmount(vo.getPayPrice());
        orderEntity.setFreightAmount(new BigDecimal("0.00"));
        orderEntity.setPromotionAmount(new BigDecimal("0.00"));
        orderEntity.setIntegrationAmount(new BigDecimal("0.00"));
        orderEntity.setCouponAmount(new BigDecimal("0"));
        orderEntity.setDiscountAmount(new BigDecimal("0"));

        //4、支付方式封装
        orderEntity.setPayAmount(new BigDecimal(vo.getPayType()+""));

        //5、订单购买积分及成长值
        orderEntity.setIntegration(1000);
        orderEntity.setGrowth(1000);
        orderEntity.setBillType(0);

        //6、自动确认收货时间
        orderEntity.setAutoConfirmDay(7);
        orderEntity.setCreateTime(new Date());
        orderEntity.setPayType(1);
        orderEntity.setStatus(0);

        //TODO 保存订单
        this.baseMapper.insert(orderEntity);

        //订单项信息
        List<OrderItemVo> cartItems = cartFeginService.getCartItems();
        List<OrderItemEntity> orderItemEntities = cartItems.stream().map(item -> {
            OrderItemEntity itemEntity = new OrderItemEntity();
            //1、查询当前购物项的spu信息
            SpuInfoVo spuInfoVo = productFeginService.spuInfo(item.getSkuId());

            //封装Spu信息
            itemEntity.setCategoryId(spuInfoVo.getCatalogId());
            itemEntity.setOrderId(orderEntity.getId());
            itemEntity.setOrderSn(orderEntity.getOrderSn());
            itemEntity.setSpuId(spuInfoVo.getId());
            itemEntity.setSpuName(spuInfoVo.getSpuName());
            itemEntity.setSpuPic(spuInfoVo.getSpuDescription());
            itemEntity.setSpuBrand(spuInfoVo.getBrandId()+"");

            //2、查询当前购物项的sku信息
            SkuInfoVo skuInfoVo = productFeginService.skuInfo(item.getSkuId());

            //封装Sku信息
            itemEntity.setSkuId(item.getSkuId());
            itemEntity.setSkuName(skuInfoVo.getSkuName());
            itemEntity.setSkuPic(item.getImage());
            itemEntity.setSkuPrice(skuInfoVo.getPrice());
            itemEntity.setSkuQuantity(item.getCount());
            String ss = "";
            for (String s : item.getSkuAttr()) {
                ss += s +";";
            }
            itemEntity.setSkuAttrsVals(ss);

            //封装价钱数据
            itemEntity.setPromotionAmount(new BigDecimal("0"));
            itemEntity.setCouponAmount(new BigDecimal("0"));
            itemEntity.setIntegrationAmount(new BigDecimal("0"));
            itemEntity.setRealAmount(new BigDecimal("0"));

            //封装积分信息
            itemEntity.setGiftGrowth(200);
            itemEntity.setGiftIntegration(200);

            return itemEntity;
        }).collect(Collectors.toList());

        //TODO 保存订单项
        orderItemService.addBath(orderItemEntities);


        //库存操作
        StringBuilder builder = new StringBuilder();
        for (OrderItemVo item : cartItems) {
            builder.append(item.getSkuId()).append("-").append(item.getCount()).append(";");
        }

        //TODO 锁库存
        R r = wareFeginService.lockWare(builder.toString());
        //TODO 改积分

        return orderEntity;
    }

}